/**
 * 项目名：五位一体化工安全信息平台
 * 日期：    2020-01-10 17:30:23
 * Copyright (c) 2015- joysuch-版权所有
 */

package com.joysuch.wwyt.risk.service.impl;

import com.joysuch.wwyt.core.common.util.PageDataUtils;
import com.joysuch.wwyt.core.common.util.PageDataUtils.PageDataConvert;
import com.joysuch.wwyt.core.common.util.SimpleDateFormatCache;
import com.joysuch.wwyt.core.exception.BusinessRestrictionsException;
import com.joysuch.wwyt.core.repository.BaseUserDao;
import com.joysuch.wwyt.core.service.BizCodeGeneratorFacade;
import com.joysuch.wwyt.risk.bean.RiskEvaluationRepoListBean;
import com.joysuch.wwyt.risk.bean.RiskEvaluationRepoListBean.Search;
import com.joysuch.wwyt.risk.entity.RiskEvaluationRepo;
import com.joysuch.wwyt.risk.entity.RiskPoint;
import com.joysuch.wwyt.risk.entity.RiskPointEvaluationJha;
import com.joysuch.wwyt.risk.entity.RiskPointEvaluationScl;
import com.joysuch.wwyt.risk.entity.dsl.QRiskEvaluationRepo;
import com.joysuch.wwyt.risk.enums.EvaluationStates;
import com.joysuch.wwyt.risk.enums.EvaluationTypes;
import com.joysuch.wwyt.risk.enums.RiskPointStates;
import com.joysuch.wwyt.risk.repository.RiskEvaluationRepoDao;
import com.joysuch.wwyt.risk.repository.RiskPointDao;
import com.joysuch.wwyt.risk.service.*;
import com.querydsl.core.types.ExpressionUtils;
import com.querydsl.core.types.Predicate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Order;
import org.springframework.stereotype.Service;

import javax.transaction.Transactional;
import java.util.List;

@Service
@Transactional
public class RiskEvaluationRepoServiceImpl implements RiskEvaluationRepoService {

    @Autowired
    private RiskEvaluationRepoDao dao;
    @Autowired
    private RiskPointService riskPointService;
    @Autowired
    private RiskDistrictService riskDistrictService;
    @Autowired
    private RiskPointDao riskPointDao;
    @Autowired
    private RiskPointEvaluationSclService evaluationSclService;
    @Autowired
    private RiskPointEvaluationJhaService evaluationJhaService;
    @Autowired
    private BizCodeGeneratorFacade bizCodeGeneratorFacade;
    @Autowired
    private BaseUserDao baseUserDao;

    @Override
    public Page<RiskEvaluationRepoListBean> findByPage(Pageable page, Search condition, EvaluationTypes type,
                                                       EvaluationStates states) {
        Predicate predicate = prepareListSearchCondition(condition);
        QRiskEvaluationRepo q = QRiskEvaluationRepo.riskEvaluationRepo;
        if (type != null) {
            predicate = ExpressionUtils.and(predicate, q.type.eq(type.getCode()));
        }
        if (states != null) {
            predicate = ExpressionUtils.and(predicate, q.state.eq(states.getCode()));
        }
        Page<RiskEvaluationRepo> data = predicate == null ? dao.findAll(page) : dao.findAll(predicate, page);

        return PageDataUtils.convertPageData(data,
                new PageDataConvert<RiskEvaluationRepoListBean, RiskEvaluationRepo>() {

                    @Override
                    public RiskEvaluationRepoListBean convert(RiskEvaluationRepo f) {
                        RiskEvaluationRepoListBean bean = new RiskEvaluationRepoListBean();
                        BeanUtils.copyProperties(f, bean, "riskDistrictId");
                        if (f.getRiskPoint() != null) {
                            bean.setRiskPointId(f.getRiskPoint().getId());
                            bean.setRiskPointName(f.getRiskPoint().getName());
                            if (f.getRiskPoint().getRiskDistrict() != null) {
                                bean.setRiskDistrictId(f.getRiskPoint().getRiskDistrict().getId());
                                bean.setRiskDistrictName(f.getRiskPoint().getRiskDistrict().getName());
                            }
                        }
                        setAnalyzeUserAndTimeInfo(f, bean);
                        return bean;
                    }

                });
    }

    protected void setAnalyzeUserAndTimeInfo(RiskEvaluationRepo f, RiskEvaluationRepoListBean bean) {
        EvaluationTypes type = EvaluationTypes.valueOf(f.getType());
        if (type == EvaluationTypes.SCL) {
            RiskPointEvaluationScl scl = evaluationSclService.findById(f.getEvaluationId());
            if (scl != null && scl.getBaseUser() != null) {
                bean.setAnalyzeUserName(scl.getBaseUser().getRealName());
            }
            if (scl != null && scl.getAnalyzeTime() != null) {
                bean.setAnalyzeTime(SimpleDateFormatCache.getFormat("yyyy年MM月dd日").format(scl.getAnalyzeTime()));
            }
        } else if (type == EvaluationTypes.JHA) {
            RiskPointEvaluationJha jha = evaluationJhaService.findById(f.getEvaluationId());
            if (jha != null && jha.getBaseUser() != null) {
                bean.setAnalyzeUserName(jha.getBaseUser().getRealName());
            }
            if (jha != null && jha.getAnalyzeTime() != null) {
                bean.setAnalyzeTime(SimpleDateFormatCache.getFormat("yyyy年MM月dd日").format(jha.getAnalyzeTime()));
            }
        }
    }

    private Predicate prepareListSearchCondition(Search condition) {
        Predicate p = null;
        QRiskEvaluationRepo q = QRiskEvaluationRepo.riskEvaluationRepo;
        if (condition.getRiskPointNameOrCode() != null) {
            p = ExpressionUtils.or(q.riskPoint.name.like("%" + condition.getRiskPointNameOrCode() + "%"),
                    q.riskPoint.code.like("%" + condition.getRiskPointNameOrCode() + "%"));
        }
        if (condition.getRiskDistrictId() != null) {
            p = ExpressionUtils.and(p, q.riskDistrictId.eq(condition.getRiskDistrictId()));
        }
        if (condition.getRiskLevel() != null) {
            p = ExpressionUtils.and(p, q.riskLevel.eq(condition.getRiskLevel()));
        }
        return p;
    }

    @Override
    public void delete(Long id) throws BusinessRestrictionsException {
        // 校验业务逻辑是否允许删除。如本数据被其他业务关联，删除后导致其他业务不可用。不能删除时将抛出业务异常
        checkBussinessRestrictions(id);
        dao.deleteById(id);
    }

    /**
     * 校验业务逻辑是否允许删除。如本数据被其他业务关联，删除后导致其他业务不可用
     *
     * @param id 要删除的业务ID
     */
    private void checkBussinessRestrictions(Long id) throws BusinessRestrictionsException {

    }

    @Override
    public RiskEvaluationRepo findById(Long id) {
        return dao.findById(id).orElse(null);
    }

    @Override
    public RiskEvaluationRepo addRiskPointEvaluation(RiskPoint riskPoint, Long riskDistrictId, EvaluationTypes type,
                                                     String method,
                                                     Long evaluationId, EvaluationStates state, Integer riskLevel) {
        return addRiskPointEvaluation(riskPoint, riskDistrictId, type, method, evaluationId, state, riskLevel, false);
    }

    @Override
    public RiskEvaluationRepo addRiskPointEvaluation(RiskPoint riskPoint, Long riskDistrictId, EvaluationTypes type,
                                                     String method,
                                                     Long evaluationId, EvaluationStates state, Integer riskLevel, boolean template) {
        RiskEvaluationRepo repo = new RiskEvaluationRepo();
        repo.setRiskPoint(riskPoint);
        repo.setRiskDistrictId(riskDistrictId);
        repo.setEvaluationId(evaluationId);
        repo.setMethod(method);
        repo.setState(state.getCode());
        repo.setRiskLevel(riskLevel);
        repo.setType(type.getCode());
        if (type == EvaluationTypes.SCL) {
            repo.setCode(bizCodeGeneratorFacade.sclPingGu());
        } else if (type == EvaluationTypes.JHA) {
            repo.setCode(bizCodeGeneratorFacade.jhaPingGu());
        }
        repo.setIsTemplate(template ? 1 : 0);
        dao.save(repo);

        //更新风险点 评估ID
        RiskPointEvaluationJha jha = evaluationJhaService.findById(evaluationId);
        riskPoint.setRiskPointEvaluationJha(jha);
        riskPointDao.save(riskPoint);
        return repo;
    }

    @Override
    public void updateStateForStaticEvaluationOfRiskPoint(Long riskPointId, EvaluationTypes type,
                                                          EvaluationStates state, Long excludeEvaluationId) {
        dao.updateStateForStaticEvaluationOfRiskPoint(riskPointId, type.getCode(), state.getCode(),
                excludeEvaluationId);
    }

    @Override
    public void updateRelatedWorkSafetyCertInfo(Long id, Long moduleId) {
        RiskEvaluationRepo evaluation = dao.findByEvaluationId(id);
        evaluation.setWorkSafetyCertId(moduleId);
        dao.save(evaluation);
    }

    @Override
    public void evaluationTakeEffect(Long id) {
        RiskEvaluationRepo repo = dao.findByEvaluationId(id);
        if (repo.getState() == EvaluationStates.UNEFFECTIVE.getCode()
                || repo.getState() == EvaluationStates.AUDIT_FAIL.getCode()) {
            repo.setState(EvaluationStates.EFFECTIVE.getCode());
            dao.save(repo);
            if (repo.getRiskPoint() != null) {
                // 2020年04月30日04:03:17 风险点shared字段为1,state为normal,不再需要更新
                RiskPoint point = repo.getRiskPoint();
                // if (point != null && !RiskPointStates.isNormal(point.getState())) {
                // riskPointService.updateRiskPointState(point.getId(), RiskPointStates.NORMAL);
                // }
                riskPointService.updateRiskPointRiskLevel(repo.getRiskPoint().getId());
                if (point.isSharedPoint() && repo.getRiskDistrictId() != null) {
                    // 共享风险点
                    riskDistrictService.updateDistrictRiskLevel(repo.getRiskDistrictId());
                }
                // 更新风险点评估级别
            } else if (repo.getRiskDistrictId() != null) {
                // 更新风险区域风险级别
            }
        }
    }

    @Override
    public List<RiskEvaluationRepo> findByRiskPointIdAndState(Long riskPointId, EvaluationStates state) {
        return dao.findByRiskPointIdAndState(riskPointId, state.getCode());
    }

    @Override
    public void evaluationAuditFail(Long evaluationId) {
        RiskEvaluationRepo repo = dao.findByEvaluationId(evaluationId);
        if (repo.getState() == 0) {
            repo.setState(EvaluationStates.AUDIT_FAIL.getCode());
            dao.save(repo);
            if (repo.getRiskPoint() != null) {
                RiskPoint point = repo.getRiskPoint();
                if (point != null && !RiskPointStates.isNormal(point.getState())) {
                    // 只能修改新建的节点状态
                    riskPointService.updateRiskPointState(point.getId(), RiskPointStates.AUDIT_FAIL);
                }
                // 更新风险点评估级别
            } else if (repo.getRiskDistrictId() != null) {
                // 更新风险区域风险级别
            }
        }
    }

    @Override
    public RiskEvaluationRepo findMostImportantByRiskPointIdAndType(Long riskPointId, EvaluationTypes type) {
        List<RiskEvaluationRepo> list = dao.findMostImportantRepoForRiskPoint(riskPointId, type.getCode(),
                EvaluationStates.EFFECTIVE.getCode());
        return list.isEmpty() ? null : list.get(0);
    }

    @Override
    public RiskPointEvaluationJha findMostImportantJhaOfRiskPoint(Long riskPointId) {
        RiskEvaluationRepo scl = findMostImportantByRiskPointIdAndType(riskPointId, EvaluationTypes.JHA);
        return scl == null ? null : evaluationJhaService.findById(scl.getEvaluationId());
    }

    @Override
    public RiskPointEvaluationScl findMostImportantSclOfRiskPoint(Long riskPointId) {
        RiskEvaluationRepo scl = findMostImportantByRiskPointIdAndType(riskPointId, EvaluationTypes.SCL);
        return scl == null ? null : evaluationSclService.findById(scl.getEvaluationId());
    }

    @Override
    public void update(RiskEvaluationRepo repo) {
        dao.save(repo);
    }

    @Override
    public RiskPointEvaluationJha findLatestJhaEvaluation() {
        RiskEvaluationRepo jha = dao.findFirstByTypeAndStateOrderByIdDesc(EvaluationTypes.JHA.getCode(),
                EvaluationStates.EFFECTIVE.getCode());
        return jha == null ? null : evaluationJhaService.findById(jha.getEvaluationId());
    }

    @Override
    public RiskPointEvaluationScl findLatestSclEvaluation() {
        RiskEvaluationRepo scl = dao.findFirstByTypeAndStateOrderByIdDesc(EvaluationTypes.SCL.getCode(),
                EvaluationStates.EFFECTIVE.getCode());
        return scl == null ? null : evaluationSclService.findById(scl.getEvaluationId());
    }

    @Override
    public void evaluationOutOfDate(Long id) {
        RiskEvaluationRepo repo = findById(id);
        if (repo != null) {
            RiskPoint one = repo.getRiskPoint();
            if (one != null) {
                if (repo != null && EvaluationStates.OUT_OF_DATE.getCode() != repo.getState()) {
                    // 更新评估状态为已过期
                    repo.setState(EvaluationStates.OUT_OF_DATE.getCode());
                    update(repo);
                    EvaluationTypes type = EvaluationTypes.valueOf(repo.getType());
                    if (type == EvaluationTypes.JHA) {
                        // 更新jha评估的状态
                        RiskPointEvaluationJha jha = findMostImportantJhaOfRiskPoint(one.getId());
                        if (jha == null) {
                            // 当前没有有效的jha评估
                            one.setJhaEvaluationState(0);
                        }
                        one.setRiskPointEvaluationJha(jha);
                        riskPointDao.save(one);
                    } else if (type == EvaluationTypes.SCL) {
                        RiskPointEvaluationScl scl = findMostImportantSclOfRiskPoint(one.getId());
                        if (scl == null) {
                            // 当前没有有效的scl评估
                            one.setSclEvaluationState(0);
                        }
                        one.setRiskPointEvaluationScl(scl);
                        riskPointDao.save(one);
                    }
                    riskPointService.updateRiskPointRiskLevel(one.getId());

                }
            }
            if (repo.getRiskDistrictId() != null) {
                riskDistrictService.updateDistrictRiskLevel(repo.getRiskDistrictId());
            }
        }
    }

    @Override
    public List<Long> findAllEvaluationIdsOfType(EvaluationTypes type) {
        return dao.findAllEvaluationIdOfType(type.getCode());
    }

    @Override
    public RiskEvaluationRepo findMostImportantNotFromWorkSafetyCertByRiskPointIdAndType(Long riskPointId,
                                                                                         EvaluationTypes type) {
        List<RiskEvaluationRepo> list = dao.findMostImportantRepoNotFromWorkSafetyCertForRiskPoint(riskPointId,
                type.getCode(), EvaluationStates.EFFECTIVE.getCode());
        return list.isEmpty() ? null : list.get(0);
    }

    @Override
    public RiskEvaluationRepo findTemplateOfRiskPoint(Long riskPointId, EvaluationTypes type) {
        QRiskEvaluationRepo q = QRiskEvaluationRepo.riskEvaluationRepo;
        Predicate p = ExpressionUtils.and(q.riskPoint.id.eq(riskPointId), q.isTemplate.eq(1));
        p = ExpressionUtils.and(p, q.type.eq(type.getCode()));
        Page<RiskEvaluationRepo> page = dao.findAll(p, PageRequest.of(0, 1, Sort.by(Order.desc("createTime"))));
        return page.isEmpty() ? null : page.getContent().get(0);
    }

    @Override
    public Integer findMostImportWorkSafetyCertRiskLevelOfDistrict(Long riskDistrictId) {
        return dao.findMostImportWorkSafetyCertRiskLevelOfDistrict(riskDistrictId,
                EvaluationStates.EFFECTIVE.getCode());
    }

}
